/*
 * Copyright Aristool AG Switzerland
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package org.opprua.tidy.beans;

import java.lang.reflect.Array;
import java.util.Date;

import org.opprua.tidy.util.TimePoint;

/**
 * TODO: add Java doc
 * 
 * Prepared for first commit: 15.07.2007
 * 
 * @author Lin Li
 */
class BeanFaker {

  private static int FAKE_STRING_LENGTH = 10;

  private static synchronized int nextInt() {
    return (int) Math.round(Math.random() * 1000000);
  }

  private BeanFaker() {
  }

  @SuppressWarnings("unchecked")
  public static <T> T fake(Class<T> c, String head) {
    if (c.isArray()) {
      Class<?> t = c.getComponentType();
      int l = nextInt() % 7;
      Object res = Array.newInstance(t, l);
      for (int i = 0; i < l; i++) {
        Object f = fake(t, head + "_" + i);
        Array.set(res, i, f);
      }
      return (T) res;
    }

    if (c.isPrimitive()) {
      if (c == int.class) {
        return (T) new Integer(nextInt() % 100);
      } else if (c == long.class) {
        return (T) new Long(nextInt() % 1000);
      } else if (c == char.class) {
        return (T) new Character((char) (nextInt() % 72 + 32));
      } else if (c == boolean.class) {
        return (T) new Boolean(nextInt() % 2 == 0);
      } else if (c == float.class) {
        return (T) new Float((nextInt() % 1000) * 0.1);
      } else if (c == double.class) { return (T) new Double(
                  (nextInt() % 10000) * 0.01); }
      return null;
    }

    if (Date.class.isAssignableFrom(c)) {
      TimePoint t = TimePoint.fake((Class<? extends Date>) c);
      return (T) t.getDate((Class<? extends Date>) c);
    }

    if (c == String.class) {
      String s = head + "_" + (nextInt() % 10000);
      if (head.length() > FAKE_STRING_LENGTH) {
        s = s.substring(s.length() - FAKE_STRING_LENGTH);
      }
      return (T) s;
    }

    Object target = BeanHandler.stuff(c);

    BeanField[] fields = (BeanField[]) BeanField.getFields(c).values().toArray(
                new BeanField[0]);
    for (int i = 0; i < fields.length; ++i) {
      try {
        fields[i].set(target, fake(fields[i].getType(), head + "_"
                    + fields[i].getName()));
      } catch (Throwable t) {}
    }
    return (T) target;
  }
}
